#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>

#include <QTimer>
#include <QDateTime>
#include <QFont>
#include <QKeyEvent>

#include <sys/time.h>






/* -------------------- 静态成员变量区域 --- 开始 ---------------------------------------------------------------------------  */

QString MainWindow::statusName[30];

/* -------------------- 静态成员变量区域 --- 结束 ---------------------------------------------------------------------------  */






/* -------------------- 构造函数区域 --- 开始 ---------------------------------------------------------------------------  */

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    this->ui = new Ui::MainWindow();

    this->mysql = QSqlDatabase::addDatabase("QMYSQL");

    this->timerClock = new QTimer(this);
    this->timerMysql = new QTimer(this);

    this->ini = new INIConfig();

    this->nt = new NetworkThread();
    this->st = new SerialThread();

    this->insertCount = -1;
    this->timeSyncRemain = 0;

    this->isRecording = false;

    this->serialStatus = false;
}

MainWindow::~MainWindow()
{
    this->st->stop();
    while(this->st->isRunning());
    delete this->st;

    this->nt->stop();
    while(nt->isRunning());
    delete this->nt;

    this->timerClock->stop();
    while(this->timerClock->isActive());
    delete this->timerClock;

    this->timerMysql->stop();
    while(this->timerMysql->isActive());
    delete this->timerMysql;

    delete ini;
    delete ui;
}

/* -------------------- 构造函数区域 --- 结束 ---------------------------------------------------------------------------  */






/* -------------------- 类私有函数区域 --- 开始 ---------------------------------------------------------------------------  */

bool MainWindow::openMysql(int count)
{
    for(int i = count, j = 1; 0 <= i; i--, j++)
    {
        if(this->mysql.open())
        {
            if(this->mysql.isOpen())
            {
                return true;
            }
        }
        qDebug() << "第" << j << "次打开数据库失败";
    }
    return false;
}

QSqlQuery *MainWindow::quertMysql(bool returnback, QString &sql)
{
    if(this->networkStstus)
    {
        qDebug() << "主线程：启动新的查询：" << sql;
        if(!this->mysql.isOpen())
        {
            if(!this->openMysql(10))
            {
                qDebug() << "主线程：数据库打开失败";
                return NULL;
            }
            qDebug() << "主线程：数据库打开成功";
        }
        QSqlQuery *query = new QSqlQuery(this->mysql);
        if(query->exec(sql))
        {
            if(query->first())
            {
                if(returnback)
                {
                    qDebug() << "主线程：查询成功";
                    return query;
                }
            }
            else
            {
                if(this->isRecording)
                {
                    this->isRecording = false;
                    this->ui->lab_veg_val->setText("<font color=\"red\">记录已经成功</font>");
                    this->countOne();
                }
                qDebug() << "主线程：执行SQL语句成功，但是无数据返回";
            }
        }
        else
        {
            qDebug() << "主线程：执行SQL语句失败";
        }
        this->freeQuery(query);
    }
    return NULL;
}

void MainWindow::freeQuery(QSqlQuery *query)
{
    qDebug() << "主线程：正在销毁一个查询器";
    query->clear();
    query->finish();
    delete query;
    qDebug() << "主线程：查询器销毁完毕";
}

void MainWindow::startMysqlRecordLoop(int timeout)
{
    if(!this->timerMysql->isActive())
    {
        this->timerMysql->setInterval(timeout);
        this->timerMysql->start();
    }
}

void MainWindow::initTabWidget(void)
{
    for(int i = 1; this->ui->tabWidgetLeft->count() > i; i++)
    {
        this->ui->tabWidgetLeft->removeTab(i);
    }
    for(int i = 1; this->ui->tabWidgetRight->count() > i; i++)
    {
        this->ui->tabWidgetRight->removeTab(i);
    }
}

void MainWindow::keybordResultsReport(QString &msg)
{
    switch(msg.at(0).toAscii())
    {
    case '2':
        {
            QString sql_select = QString("SELECT `员工姓名` FROM `%1` WHERE find_in_set('%2', `员工ID`)").arg(this->ini->farmertable).arg(msg);
            QString sql_log = QString("INSERT INTO `%1` (`接收条码`, `入库时间`, `称号`) VALUES ('%2', now(), '%3')").arg(this->ini->logtable).arg(msg).arg(this->ini->myid);
            QSqlQuery *query = this->quertMysql(true, sql_select);
            if(NULL != query)
            {
                if(query->first())
                {
                    this->ui->lab_name_val->setText(query->value(0).toString());
                    this->ui->lab_mid_val->setText(msg);
                    this->startMysqlRecordLoop(20);
                }
                this->freeQuery(query);
            }
            else
            {
                if(this->networkStstus)
                {
                    this->ui->lab_name_val->setText("<font color=\"red\">请重新扫码</font>");
                }
                else
                {
                    this->ui->lab_name_val->setText("<font color=\"red\">请检查网线是否插好</font>");
                }
            }
            this->quertMysql(false, sql_log);
        }
        break;
    case '8':
        {
            QString sql_select = QString("SELECT `品种名` FROM `%1` WHERE find_in_set('%2', `条形码`)").arg(this->ini->vegetable).arg(msg);
            QString sql_log = QString("INSERT INTO `%1` (`接收条码`, `入库数量`, `入库时间`, `称号`) VALUES ('%2', '%3', now(), '%4')").arg(this->ini->logtable).arg(msg).arg(this->ui->lcdNumber->value()).arg(this->ini->myid);
            QSqlQuery *query = this->quertMysql(true, sql_select);
            if(NULL != query)
            {
                if(query->first())
                {
                    this->ui->lab_veg_val->setText(query->value(0).toString());
                    this->ui->lab_vid_val->setText(msg);
                    this->startMysqlRecordLoop(20);
                }
                this->freeQuery(query);
            }
            else
            {
                if(this->networkStstus)
                {
                    this->ui->lab_name_val->setText("<font color=\"red\">请重新扫码</font>");
                }
                else
                {
                    this->ui->lab_name_val->setText("<font color=\"red\">请检查网线是否插好</font>");
                }
            }
            this->quertMysql(false, sql_log);
        }
        break;
    default:
        break;
    }
}

void MainWindow::countOne(void)
{
    this->insertCount++;
    qDebug() << "主线程：计数加1，当前值为：" << this->insertCount;
    this->ui->lab_count_val->setText(QString::number(this->insertCount));
}

/* -------------------- 类私有函数区域 --- 结束 ---------------------------------------------------------------------------  */






/* -------------------- 槽函数区域 --- 开始 ---------------------------------------------------------------------------  */

void MainWindow::slot_RefreshClock(void)
{
    if(0 >= this->timeSyncRemain && this->networkStstus)
    {
        qDebug() << "主线程：开始同步时间";
        if(this->timerClock->isActive())
        {
            this->timerClock->stop();
        }
        QString sql = QString("SELECT UNIX_TIMESTAMP(NOW())");
        QSqlQuery *query = this->quertMysql(true, sql);
        if(NULL != query)
        {
            struct timeval tv;
            if(query->first())
            {
                tv.tv_sec = (time_t)query->value(0).toInt() + 1;
            }
            this->freeQuery(query);
            if(1420041600 < tv.tv_sec)
            {
                settimeofday(&tv, NULL);
                this->timeSyncRemain = this->ini->synctimeout;
                qDebug() << "主线程：同步时间成功，新值为：" << tv.tv_sec;
            }
            else
            {
                qDebug() << "主线程：时间值异常，必须在2015年1月1日之后的日期";
                return;
            }
        }
        else
        {
            qDebug() << "主线程：同步时间失败，将在下一次再次同步";
            return;
        }
        this->timerClock->setInterval(1000);
        this->timerClock->start();
    }
    else if(this->networkStstus)
    {
            this->timeSyncRemain--;
    }
    this->ui->lab_time_val->setText(QDateTime::currentDateTime().toString("hh:mm:ss"));
}

void MainWindow::slot_MysqlRecordLoop(void)
{
    if(this->networkStstus && this->lock.tryLock())
    {
        QString name = this->ui->lab_name_val->text();
        if(!name.isEmpty())
        {
            QString mid = this->ui->lab_mid_val->text();
            if(!mid.isEmpty())
            {
                QString vname = this->ui->lab_veg_val->text();
                if(!vname.isEmpty())
                {
                    QString vid = this->ui->lab_vid_val->text();
                    if(!vid.isEmpty())
                    {
                        double heft = this->ui->lcdNumber->value();
                        if(0.0 < heft)
                        {
                            this->ui->lab_name_val->setText("");
                            this->ui->lab_mid_val->setText("");
                            this->ui->lab_veg_val->setText("");
                            this->ui->lab_vid_val->setText("");

                            this->timerMysql->stop();
                            while(this->timerMysql->isActive());

                            this->isRecording = true;

                            QString sql = QString("INSERT INTO `%1` (`员工ID`, `入库品种`, `入库数量`, `入库单位`, `入库时间`, `称号`) VALUES ('%2', '%3', '%4', '斤', now(), '%5')").arg(this->ini->datatable).arg(mid).arg(vname).arg(heft).arg(this->ini->myid);
                            this->quertMysql(false, sql);
                        }
                    }
                }
            }
        }
        this->lock.unlock();
    }
}

void MainWindow::slot_NetworkStatus(int status)
{
    if(0 == status)                     // 网络正常
    {
        this->networkStstus = true;     // 网络状态标志为正常

        if(!this->st->isRunning())      // 串口线程没运行就启动它
        {
            this->st->start();
            this->serialStatus = true;
        }
        if(!this->timerClock->isActive())   // 时钟线程没运行就启动它
        {
            this->timerClock->setInterval(1000);
            this->timerClock->start();
        }
        if(this->serialStatus)          // 串口OK就更新网络状态，主要是防止提示信息冲突
        {
            this->ui->lab_stat_val->setText(MainWindow::statusName[2]);
        }
    }
    else if(1 == status)                // 网络不可用
    {
        this->networkStstus = false;    // 网络状态标志为异常

        if(this->st->isRunning())       // 关闭串口线程
        {
            this->st->stop();
            while(this->st->isRunning());   // 等待串口线程正常关闭
        }

        this->serialStatus = true;      // 重置串口工作状态为正常
        this->slot_HeftValue(0.0);      // 清空重量值

        if(this->mysql.isOpen())        // 关闭Mysql连接
        {
            this->mysql.close();
        }

        if(this->serialStatus)          // 串口OK就更新网络状态，主要是防止提示信息冲突
        {
            this->ui->lab_stat_val->setText(MainWindow::statusName[1]);
        }
    }
}

void MainWindow::slot_HeftValue(double num)
{
    this->ui->lcdNumber->display(QString::number(num, 'f', 2));
}


void MainWindow::slot_SerialStatus(int status)
{
    if(1 == status)
    {
        this->serialStatus = false;
        this->ui->lab_stat_val->setText(MainWindow::statusName[4]);
    }
    else if(2 == status)
    {
        this->serialStatus = false;
        this->ui->lab_stat_val->setText(MainWindow::statusName[5]);
    }
    else if(3 == status)
    {
        this->serialStatus = false;
        this->ui->lab_stat_val->setText(MainWindow::statusName[6]);
    }
    else
    {
        this->serialStatus = true;
    }
}

/* -------------------- 槽函数区域 --- 结束 ---------------------------------------------------------------------------  */





/* -------------------- 类成员函数区域 --- 开始 ---------------------------------------------------------------------------  */

bool MainWindow::initConfig(const char *inipath)
{
    qDebug() << "主线程：准备从INI文件中获取配置参数，路径为" << inipath;
    if(!this->ini->initValue(inipath))
    {
        qDebug() << "主线程：从INI文件中获取配置参数失败，请检查上方出错信息";
        return false;
    }

    this->ini->dumpAll();

    qDebug() << "主线程：从INI文件中获取配置参数成功";
    return true;
}

bool MainWindow::initConnect()
{
    qDebug() << "主线程：准备初始化信号通道";
    this->connect(this->timerClock, SIGNAL(timeout()), this, SLOT(slot_RefreshClock()));
    this->connect(this->timerMysql, SIGNAL(timeout()), this, SLOT(slot_MysqlRecordLoop()));
    this->connect(this->nt, SIGNAL(Network2UI_UpdateStatusSignal(int)), this, SLOT(slot_NetworkStatus(int)));
    this->connect(this, SIGNAL(UI2Network_StartSignal(bool)), this->nt, SLOT(slot_SetUIIsOK(bool)));
    this->connect(this->st, SIGNAL(Serial2UI_UpdateValueSignal(double)), this, SLOT(slot_HeftValue(double)));
    this->connect(this->st, SIGNAL(Serial2UI_ReportFailSignal(int)), this, SLOT(slot_SerialStatus(int)));
    qDebug() << "主线程：信号通道初始化成功";
    return true;
}

int MainWindow::initThread()
{
    qDebug() << "主线程：准备初始化线程";

    if(!this->mysql.isDriverAvailable("QMYSQL"))
    {
        qDebug() << "主线程：数据库驱动不可用";
        return 1;
    }

    // TODO: 网络线程初始化
    if(!this->nt->initNetwork(this->ini->ifname, this->ini->staticip, this->ini->staticnetmask, this->ini->staticgatway, this->ini->dns1, this->ini->dns2))
    {
        qDebug() << "主线程：网络线程初始化失败";
        return 2;
    }

    // TODO: 串口线程初始化
    if(!this->st->initSerial(this->ini->serialpath, this->ini->serialrate, this->ini->serialdatabit, this->ini->serialstopbit, this->ini->serialseparate, this->ini->serialdatavalidlen, this->ini->serialreadinterval, this->ini->serialbufferlen))
    {
        qDebug() << "主线程：串口线程初始化失败";
        return 3;
    }
    else
    {
        this->serialStatus = true;
    }

    qDebug() << "主线程：线程初始化成功";
    return 0;
}

bool MainWindow::startThread(void)
{
    qDebug() << "主线程：准备启动线程";

    if(this->nt->isInitOK() && this->st->isInitOK())
    {
        this->nt->start();
        qDebug() << "主线程：线程启动成功";
        return true;
    }
    qDebug() << "主线程：线程启动失败";
    return false;
}

bool MainWindow::initWindows()
{
    qDebug() << "主线程：准备初始化窗体";

    this->ui->setupUi(this);

    // TODO：配置图形界面
    this->setStyleSheet("QMainWindow{background-image: url(/usr/local/Trolltech/QtEmbedded-4.8.5-arm/bin/background.jpg)}");
    this->showFullScreen();
    this->ui->menuBar->setVisible(false);
    this->ui->mainToolBar->setVisible(false);
    this->ui->statusBar->setVisible(false);

    this->initTabWidget();              // TOOD：初始化Tab

    if(13 < this->ini->codemaxlen)      // TODO：根据条形码长度调整扫码框的字体大小
    {
        QFont font = this->ui->textedit_code->font();
        font.setPointSize(font.pointSize() - (this->ini->codemaxlen - 13));
        this->ui->textedit_code->setFont(font);
    }

    // TODO：初始化界面lab
    this->ui->lab_stat_val->setText(MainWindow::statusName[0]);
    this->ui->lab_time_val->setText(MainWindow::statusName[3]);
    this->slot_HeftValue(0.0);
    this->countOne();

    // TODO：初始化数据库参数
    this->mysql.setHostName(this->ini->serverip);
    this->mysql.setPort(this->ini->serverport);
    this->mysql.setDatabaseName(this->ini->databasename);
    this->mysql.setUserName(this->ini->username);
    this->mysql.setPassword(this->ini->password);

    // TODO：通知网络线程启动
    emit this->UI2Network_StartSignal(true);

    qDebug() << "主线程：窗体初始化已完成";
    return true;
}

void MainWindow::keyPressEvent(QKeyEvent *k)
{
    // 防止正在查询数据库时或者网络故障时录入
    if(!this->isRecording && this->networkStstus)
    {
        int x = k->key();                                                   // 保存键值
        QString str = this->ui->textedit_code->text();                      // 获取输入框已存在的数据到变量str中
        this->ui->textedit_code->setText("");                               // 清空输入框

        // TODO: 过滤第一个字符
        // 当str为空，且键值不是2或者8，直接丢弃
        if(0 == str.length() && Qt::Key_2 != x && Qt::Key_8 != x)
        {
            return;
        }

        // TODO：输入第一个字符时，清空相应文本框
        if(0 == str.length() && (Qt::Key_2 == x || Qt::Key_8 == x))
        {
            if(Qt::Key_2 == x)
            {
                this->ui->lab_name_val->setText("");        // 清空员工姓名
                this->ui->lab_mid_val->setText("");         // 清空员工编号
                QString lab_vid = this->ui->lab_vid_val->text();
                if(lab_vid.isEmpty())
                {
                    this->ui->lab_veg_val->setText("");
                }
            }
            if(Qt::Key_8 == x)
            {
                this->ui->lab_veg_val->setText("");         // 清空品种名称
                this->ui->lab_vid_val->setText("");         // 清空品种编号

                // TODO：此处用于菜名确认用途
                // 如果员工还未录入，那么录入菜名无效
                QString lab_name = this->ui->lab_name_val->text();
                if(lab_name.isEmpty())
                {
                    return;     // 员工名还未获取到，丢弃
                }
                else
                {
                    QString lab_mid = this->ui->lab_mid_val->text();
                    if(lab_mid.isEmpty())
                    {
                        return;     // 员工号还未录入，丢弃
                    }
                }
            }
        }

        // TODO：正常录入
        if(Qt::Key_0 <= x && Qt::Key_9 >= x)
        {
            // TODO：判断长度是否超出限制
            // 同时过滤第一个非法字符
            if(this->ini->codemaxlen <= str.length())
            {
                str.clear();    // 清空

                // TODO：录入无效，重录
                // 当前字符当成第一个输入
                // 首字符不是2和8，直接返回
                if(Qt::Key_2 != x && Qt::Key_8 != x)
                {
                    return;
                }
            }

            // TODO：正常录入，将新字符加入
            str.append(x);

            // TODO：更新到图形界面
            this->ui->textedit_code->setText(str);
        }
        else if(Qt::Key_Return == x || Qt::Key_Enter == x)  //接收回车键
        {
            char ch = str.at(0).toAscii();                  // 取出首字符

            // TODO：判断长度和首字符是否合法
            if(this->ini->codemaxlen == str.length() && ('2' == ch || '8' == ch))
            {
                this->keybordResultsReport(str);            // 查询数据库
            }
        }
    }
    else
    {
        this->ui->textedit_code->setText("请稍等");
    }
}

/* -------------------- 类成员函数区域 --- 结束 ---------------------------------------------------------------------------  */
